package com.ygqh.baby.service.impl;

import com.ygqh.baby.ao.DataStatus;
import com.ygqh.baby.ao.QueryInfo;
import com.ygqh.baby.ao.ResultSet;
import com.ygqh.baby.mapper.YgSearchWordsMapper;
import com.ygqh.baby.po.YgSearchWords;
import com.ygqh.baby.po.YgSearchWordsExample;
import com.ygqh.baby.service.YgSearchWordsService;
import com.ygqh.baby.template.AbstractSplitListTemplate;
import com.ygqh.baby.utils.ExceptionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author Ss
 */
@Service
public class YgSearchWordsServiceImpl implements YgSearchWordsService {

	private final static ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(10);
	private final static Logger LOGGER = LoggerFactory.getLogger(YgSearchWordsServiceImpl.class);

	@Autowired
	private YgSearchWordsMapper ygSearchWordsMapper;

	@Override
	public List<YgSearchWords> find() {
		YgSearchWordsExample example = new YgSearchWordsExample();
		example.createCriteria().andStatusEqualTo(DataStatus.Valid.name());
		return ygSearchWordsMapper.selectByExample(example);
	}

	@Override
	public int findCount() {
		YgSearchWordsExample example = new YgSearchWordsExample();
		example.createCriteria().andStatusEqualTo(DataStatus.Valid.name());
		return ygSearchWordsMapper.countByExample(example);
	}

	@Override
	public YgSearchWords findById(Long id) {
		return ygSearchWordsMapper.selectByPrimaryKey(id);
	}

	@Override
	public int save(YgSearchWords ygSearchWords) {
		return ygSearchWordsMapper.insertSelective(ygSearchWords);
	}

	@Override
	public int update(YgSearchWords ygSearchWords) {
		return ygSearchWordsMapper.updateByPrimaryKeySelective(ygSearchWords);
	}

	@Override
	public int deleteSoft(Long[] ids) {
		Assert.notEmpty(ids);
		YgSearchWordsExample example = new YgSearchWordsExample();
		example.createCriteria().andIdIn(Arrays.asList(ids));
		YgSearchWords record = new YgSearchWords();
		record.setStatus(DataStatus.Delete);
		return ygSearchWordsMapper.updateByExampleSelective(record, example);
	}

	@Override
	public int deleteSoft(Long id) {
		return this.deleteSoft(new Long[]{id});
	}

	@Override
	public int saveOrUpdate(YgSearchWords ygSearchWords) {
		int r;
		if (ygSearchWords.getId() != null) {
			r = this.update(ygSearchWords);
		} else {
			r = this.save(ygSearchWords);
		}
		return r;
	}

	@Override
	public ResultSet<YgSearchWords> search(QueryInfo queryInfo, String words, Long minHot, DataStatus status) {
		int count = ygSearchWordsMapper.countSuper(words, minHot, status);
		if (count == 0) {
			return new ResultSet<>();
		}
		List<YgSearchWords> list = ygSearchWordsMapper.selectSuper(queryInfo, words, minHot, status);
		return new ResultSet<>(count, list);
	}

//	@Cacheable(cacheNames = "redis", key = "'seachwords:words_id_'+#words+'_'+#limit")
	@Override
	public List<String> findValidWords(String words, Integer limit) {
		if (StringUtils.isEmpty(words)) {
			return null;
		}
		if (limit == null) {
			limit = 10;
		}
		List<String> list = ygSearchWordsMapper.selectValidWords(words, limit);
		if (!CollectionUtils.isEmpty(list)) {
			list.sort(Comparator.comparingInt(String::length));
		}
		return list;
	}

	@Override
	public YgSearchWords findWords(String words, DataStatus status) {
		Assert.notNull(words, "param words can't be null");
		return ygSearchWordsMapper.selectWords(words, status);
	}

	@Override
	public void addAsync(YgSearchWords record) {
		if (StringUtils.isEmpty(record.getWords())) {
			return;
		}
		EXECUTOR_SERVICE.execute(() -> {
			try {
				addRecord(record);
			} catch (Exception e) {
				if (e instanceof DuplicateKeyException) {
					// 搜索词更新到数据库，考虑到保存并发的问题，给予1次重试的机会
					addRecord(record);
				} else {
					e.printStackTrace();
					LOGGER.warn("搜索词更新到数据库异常，" + ExceptionUtil.getExceptionMsg(e));
				}
			}
		});
	}

	/**
	 * 更新搜索词到数据库
	 *
	 * @param record
	 */
	@Override
	public void addRecord(YgSearchWords record) {
		YgSearchWords searchWords = findWords(record.getWords(), null);
		if (searchWords != null) {
			record.setId(searchWords.getId());
			updateHot(record);
		} else {
			save(record);
		}
	}

	@Override
	public List<YgSearchWords> findByStatus(Date minUpdateTime, DataStatus... status) {
		return ygSearchWordsMapper.selectByStatus(minUpdateTime, status);
	}

	@Override
	public int updateStatus(List<YgSearchWords> searchWordsList) {
		return new AbstractSplitListTemplate<YgSearchWords>(searchWordsList) {
			@Override
			public int execute(List<YgSearchWords> recordList) {
				return ygSearchWordsMapper.updateStatus(recordList);
			}
		}.split();
	}

	/**
	 * 搜索词热度+1
	 *
	 * @param record
	 * @return
	 */
	private int updateHot(YgSearchWords record) {
		return ygSearchWordsMapper.updateHot(record);
	}
}

